package com.czk.run;

import com.czk.commons.MethodStackMapFrameVisitor;
import com.czk.utils.FileUtil;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;

/**
 * 为每个instruction生成frame
 * 注意：生成的字节码文件方法code每一行代表一个instruction
 * 压缩frames
 * 为了让.class文件占用的存储空间尽可能的小，因此要对frames进行压缩。对frames进行压缩，从本质上来说，就是忽略掉一些不重要的frames，
 * 而只留下一些重要的frames。
 * <p>
 * 那么，怎样区分哪些frames重要，哪些frames不重要呢？我们从instruction执行顺序的角度来看待这个问题。
 * <p>
 * 如果说，instruction是按照“一个挨一个向下顺序执行”的，那么它们对应的frames就不重要；相应的，instruction在执行过程时，
 * 它是从某个地方“跳转”过来的，那么对应的frames就重要。为什么说instruction是按照“一个挨一个向下顺序执行”的，那么它们对应的frames就不重要呢？
 * 因为这些instruction对应的frame可以很容易的推导出来。如果当前的instruction是从某个地方跳转过来的，就必须要记录它执行之前的frame的情况，
 * 否则就没有办法计算它执行之后的frame的情况。当然，我们这里讲的只是大体的思路，而不是具体的判断细节。
 * <p>
 * 经过压缩之后的frames，就存放在ClassFile的StackMapTable结构中。
 *
 * @Author:ChenZhangKun
 * @Date: 2021/7/27 17:28
 */
public class FrameCore {
    public static void main(String[] args) {
     /*   String relative_path = "sample/HelloWorld.class";
        String filepath = FileUtil.getFilePath(relative_path);*/
        String filePath = "F:\\IdeaProjects\\asm\\target\\classes\\com\\czk\\sample\\HelloWorlds.class";
        byte[] bytes = FileUtil.readBytes(filePath);
        if (bytes == null) {
            throw new RuntimeException("bytes is null");
        }

        //（1）构建ClassReader
        ClassReader cr = new ClassReader(bytes);

        //（2）构建ClassVisitor
        int api = Opcodes.ASM9;
        ClassVisitor cv = new MethodStackMapFrameVisitor(api, null);

        //（3）结合ClassReader和ClassVisitor
        int parsingOptions = ClassReader.EXPAND_FRAMES; // 注意，这里使用了EXPAND_FRAMES
        cr.accept(cv, parsingOptions);
    }
}
